﻿/********************************************************************
	日期:2022/03/27
	名称:ResSvc
	邮箱:yunnibbd@163.com
	作者:yunni
	描述:资源服务
*********************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Net.Security;
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Xml;
using UnityEngineInternal;

public class ResSvc : MonoBehaviour{
    public static ResSvc Instance;

    private Action prgCB = null;

    public void InitRes(){
        Instance = this;
        InitRDNameCfg(PathDefine.RDNameCfg);
        InitMonsterCfg(PathDefine.MonsterCfg);
        InitMapCfg(PathDefine.MapCfg);
        InitGuideCfg(PathDefine.GuideConfig);
        InitStrongCfg(PathDefine.StrongCfg);
        InitTaskCfg(PathDefine.TaskCfg);
        InitSkillCfg(PathDefine.SkillCfg);
        InitSkillMoveCfg(PathDefine.SkillMoveCfg);
        InitSkillActionCfg(PathDefine.SkillActionCfg);
        PECommon.Log("Init ResSvc");
    }

    public void ResetSkillCfgs(){
        skillDic.Clear();
        skillMoveDic.Clear();
        InitSkillCfg(PathDefine.SkillCfg);
        InitSkillMoveCfg(PathDefine.SkillMoveCfg);
        PECommon.Log("ResetSkillCfgs...");
    }

    /*
     * @brief 异步加载场景
     * @param sceneName 场景名称
     * @param afterCB 加载完场景后的回调函数
     */
    public void AsyncLoadScene(string sceneName, Action afterCb){
        GameRoot.Instance.loadingWnd.SetWndState();
        AsyncOperation sceneAsync = SceneManager.LoadSceneAsync(sceneName);
        prgCB = () => {
            float val = sceneAsync.progress;
            GameRoot.Instance.loadingWnd.SetProgres(val);
            if (val == 1){
                sceneAsync = null;
                GameRoot.Instance.loadingWnd.SetWndState(false);
                prgCB = null;
                if (afterCb != null){
                    afterCb();
                }
            }
        };
    }

    private void Update(){
        if (prgCB != null){
            prgCB();
        }
    }

    private Dictionary<string, AudioClip> adDic = new Dictionary<string, AudioClip>();

    public AudioClip LoadAudio(string path, bool cache = false){
        AudioClip au = null;
        if (!adDic.TryGetValue(path, out au)){
            au = Resources.Load<AudioClip>(path);
            if (cache){
                adDic.Add(path, au);
            }
        }

        return au;
    }

    private Dictionary<string, GameObject> goDic = new Dictionary<string, GameObject>();

    public GameObject LoadPrefab(string path, bool cache = false){
        GameObject prefab = null;
        if (!goDic.TryGetValue(path, out prefab)){
            prefab = Resources.Load<GameObject>(path);
            if (cache){
                this.goDic.Add(path, prefab);
            }
        }

        GameObject go = null;
        if (prefab != null){
            go = Instantiate(prefab);
        }

        return go;
    }

    private Dictionary<string, Sprite> spDic = new Dictionary<string, Sprite>();
    public Sprite LoadSprite(string path, bool cache = false){
        Sprite sp = null;
        if (!spDic.TryGetValue(path, out sp)){
            sp = Resources.Load<Sprite>(path);
            if (cache){
                spDic.Add(path, sp);
            }
        }

        return sp;
    }

    #region InitCfgs

    #region 随机名字

    private List<string> surnameList = new List<string>();
    private List<string> manList = new List<string>();
    private List<string> womanList = new List<string>();

    private void InitRDNameCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file:" + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                //var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    switch (xmlElement.Name){
                        case "surname":
                            surnameList.Add(xmlElement.InnerText);
                            break;
                        case "man":
                            manList.Add(xmlElement.InnerText);
                            break;
                        case "woman":
                            womanList.Add(xmlElement.InnerText);
                            break;
                    }
                }
            }
        }
    }

    public string GetRDNameData(bool man = true){
        //System.Random rd = new System.Random();
        string rdName = surnameList[PETools.RDInt(0, surnameList.Count - 1)];
        if (man){
            rdName += manList[PETools.RDInt(0, manList.Count - 1)];
        }
        else{
            rdName += womanList[PETools.RDInt(0, womanList.Count - 1)];
        }

        return rdName;
    }

    #endregion

    #region 地图

    private Dictionary<int, MapCfg> mapCfgDataDic = new Dictionary<int, MapCfg>();

    private void InitMapCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file:" + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                MapCfg mc = new MapCfg{
                    ID = ID,
                    monsterLst = new List<MonsterData>()
                };
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    switch (xmlElement.Name){
                        case "mapName":
                            mc.mapName = xmlElement.InnerText;
                            break;
                        case "sceneName":
                            mc.sceneName = xmlElement.InnerText;
                            break;
                        case "mainCamPos":{
                            string[] valArr = xmlElement.InnerText.Split(',');
                            mc.mainCamPos = new Vector3(float.Parse(valArr[0]), float.Parse(valArr[1]),
                                float.Parse(valArr[2]));
                        }
                            break;
                        case "mainCamRote":{
                            string[] valArr = xmlElement.InnerText.Split(',');
                            mc.mainCamRote = new Vector3(float.Parse(valArr[0]), float.Parse(valArr[1]),
                                float.Parse(valArr[2]));
                        }
                            break;
                        case "playerBornPos":{
                            string[] valArr = xmlElement.InnerText.Split(',');
                            mc.playerBornPos = new Vector3(float.Parse(valArr[0]), float.Parse(valArr[1]),
                                float.Parse(valArr[2]));
                        }
                            break;
                        case "playerBornRote":{
                            string[] valArr = xmlElement.InnerText.Split(',');
                            mc.playerBornRote = new Vector3(float.Parse(valArr[0]), float.Parse(valArr[1]),
                                float.Parse(valArr[2]));
                        }
                            break;
                        case "power":
                            mc.power = int.Parse(xmlElement.InnerText);
                            break;
                        case "monsterLst":{
                            string[] valArr = xmlElement.InnerText.Split('#');
                            for (int j = 0; j < valArr.Length; j++){
                                if (j == 0){
                                    continue;
                                }

                                string[] tempArr = valArr[j].Split('|');
                                for (int k = 0; k < tempArr.Length; k++){
                                    if (k == 0){
                                        continue;
                                    }

                                    string[] arr = tempArr[k].Split(',');
                                    MonsterData md = new MonsterData{
                                        ID = int.Parse(arr[0]),
                                        mWava = j,
                                        mIndex = k,
                                        mCfg = GetMonsterCfgData(int.Parse(arr[0])),
                                        mBornPos = new Vector3(float.Parse(arr[1]), float.Parse(arr[2]), float.Parse(arr[3])),
                                        mBornRote = new Vector3(0, float.Parse(arr[4]), 0),
                                        mLevel = int.Parse(arr[5]),
                                    };
                                    mc.monsterLst.Add(md);
                                }
                            }
                        }
                            break;
                    }
                }

                mapCfgDataDic.Add(ID, mc);
            }
        }
    }

    public MapCfg GetMapCfgData(int id){
        MapCfg cfg;
        if (this.mapCfgDataDic.TryGetValue(id, out cfg)){
            return cfg;
        }

        return null;
    }

    #endregion

    #endregion

    #region 自动引导配置

    private Dictionary<int, AutoGuideCfg> guideTaskDic = new Dictionary<int, AutoGuideCfg>();
    private void InitGuideCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file: " + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                AutoGuideCfg mc = new AutoGuideCfg{
                    ID = ID
                };
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    switch (xmlElement.Name){
                        case "npcID":
                            mc.npcID = int.Parse(xmlElement.InnerText);          
                            break;
                        case "dilogArr":
                            mc.dialogArr = xmlElement.InnerText;
                            break;
                        case "actID":
                            mc.actID = int.Parse(xmlElement.InnerText);
                            break;
                        case "coin":
                            mc.coin = int.Parse(xmlElement.InnerText);
                            break;
                        case "exp":
                            mc.exp = int.Parse(xmlElement.InnerText);
                            break;
                    }
                }
                guideTaskDic.Add(ID, mc);
            }
        }
    }

    public AutoGuideCfg GetAutoGuideData(int id){
        AutoGuideCfg agc = null;
        if (guideTaskDic.TryGetValue(id, out agc)){
            return agc;
        }
        return null;
    }

    #endregion

    #region  Strong 强化

    private Dictionary<int, Dictionary<int, StrongCfg>> strongDic = new Dictionary<int, Dictionary<int, StrongCfg>>();

    private void InitStrongCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file: " + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                StrongCfg sc = new StrongCfg{
                    ID = ID
                };
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    int val = int.Parse(xmlElement.InnerText);
                    switch (xmlElement.Name){
                        case "pos":
                            sc.pos = val;
                            break;
                        case "addhp":
                            sc.addhp = val;
                            break;
                        case "addhurt":
                            sc.addhurt = val;
                            break;
                        case "adddef":
                            sc.adddef = val;
                            break;
                        case "minlv":
                            sc.minlv = val;
                            break;
                        case "starlv":
                            sc.starlv = val;
                            break;
                        case "coin":
                            sc.coin = val;
                            break;
                        case "crystal":
                            sc.crystal = val;
                            break;
                    }
                }
                Dictionary<int, StrongCfg> dic = null;
                if (strongDic.TryGetValue(sc.pos, out dic)){
                    dic.Add(sc.starlv, sc);
                }
                else{
                    dic = new Dictionary<int, StrongCfg>();
                    dic.Add(sc.starlv, sc);
                    strongDic.Add(sc.pos, dic);
                }
            }
        }
    }

    public StrongCfg GetStrongData(int pos, int starlv){
        StrongCfg ret = null;
        Dictionary<int, StrongCfg> dic = null;
        if (strongDic.TryGetValue(pos, out dic)){
            ret = dic[starlv];
        }
        return ret;
    }

    public int GetPropAddValPreLv(int pos, int starlv, int type){
        Dictionary<int, StrongCfg> posDic = null;
        int val = 0;
        if (strongDic.TryGetValue(pos, out posDic)){
            for (int i = 0; i < starlv; i++){
                StrongCfg sc;
                if (posDic.TryGetValue(i, out sc)){
                    switch (type){
                        case 1: //血量
                            val += sc.addhp;        
                            break;
                        case 2: //伤害
                            val += sc.addhurt;
                            break;
                        case 3: //防御
                            val += sc.adddef;
                            break;
                    }
                }
            }
        }

        return val;
    }
    
    #endregion
    
    #region 任务配置

    private Dictionary<int, TaskRewardCfg> taskDic = new Dictionary<int, TaskRewardCfg>();
    private void InitTaskCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file: " + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                TaskRewardCfg trc = new TaskRewardCfg{
                    ID = ID
                };
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    switch (xmlElement.Name){
                        case "taskName":
                            trc.taskName = xmlElement.InnerText;
                            break;
                        case "count":
                            trc.count = int.Parse(xmlElement.InnerText);
                            break;
                        case "exp":
                            trc.exp = int.Parse(xmlElement.InnerText);
                            break;
                        case "coin":
                            trc.coin = int.Parse(xmlElement.InnerText);
                            break;
                    }
                }
                taskDic.Add(ID, trc);
            }
        }
    }

    public TaskRewardCfg GetTaskData(int id){
        TaskRewardCfg agc = null;
        if (taskDic.TryGetValue(id, out agc)){
            return agc;
        }
        return null;
    }

    #endregion
    
    #region 技能配置
    private Dictionary<int, SkillCfg> skillDic = new Dictionary<int, SkillCfg>();
    private void InitSkillCfg(string path) {
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml) {
            PECommon.Log("xml file:" + path + " not exist", LogType.Error);
        }
        else {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml.text);

            XmlNodeList nodLst = doc.SelectSingleNode("root").ChildNodes;

            for (int i = 0; i < nodLst.Count; i++) {
                XmlElement ele = nodLst[i] as XmlElement;

                if (ele.GetAttributeNode("ID") == null) {
                    continue;
                }
                int ID = Convert.ToInt32(ele.GetAttributeNode("ID").InnerText);
                SkillCfg sc = new SkillCfg {
                    ID = ID,
                    skillMoveLst = new List<int>(),
                    skillActionLst = new List<int>(),
                    skillDamageLst = new List<int>()
                };

                foreach (XmlElement e in nodLst[i].ChildNodes) {
                    switch (e.Name) {
                        case "skillName":
                            sc.skillName = e.InnerText;
                            break;
                        case "skillTime":
                            sc.skillTime = int.Parse(e.InnerText);
                            break;
                        case "aniAction":
                            sc.aniAction = int.Parse(e.InnerText);
                            break;
                        case "cdTime":
                            sc.cdTime = int.Parse(e.InnerText);
                            break;
                        case "fx":
                            sc.fx = e.InnerText;
                            break;
                        case "dmgType":
                            if (e.InnerText.Equals("1")){
                                sc.dmgType = DamageType.AD;
                            }
                            else if (e.InnerText.Equals("2")){
                                sc.dmgType = DamageType.AP;
                            }
                            break;
                        case "skillMoveLst":
                            string[] strings = e.InnerText.Split('|');
                            for (int j = 0; j < strings.Length; j++){
                                if (strings[j] != ""){
                                    sc.skillMoveLst.Add(int.Parse(strings[j]));
                                }
                            }
                            break;
                        case "skillActionLst":
                            string[] skillActionArr = e.InnerText.Split('|');
                            for (int j = 0; j < skillActionArr.Length; j++){
                                if (skillActionArr[j] != ""){
                                    sc.skillActionLst.Add(int.Parse(skillActionArr[j]));
                                }
                            }
                            break;
                        case "skillDamageLst":
                            string[] skillDamageArr = e.InnerText.Split('|');
                            for (int j = 0; j < skillDamageArr.Length; j++){
                                if (skillDamageArr[j] != ""){
                                    sc.skillDamageLst.Add(int.Parse(skillDamageArr[j]));
                                }
                            }
                            break;
                    }
                }
                skillDic.Add(ID, sc);
            }
        }
    }
    public SkillCfg GetSkillCfg(int id) {
        SkillCfg sc = null;
        if (skillDic.TryGetValue(id, out sc)) {
            return sc;
        }
        return null;
    }
    #endregion

    #region 技能配置
    private Dictionary<int, SkillActionCfg> skillActionDic = new Dictionary<int, SkillActionCfg>();
    private void InitSkillActionCfg(string path) {
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml) {
            PECommon.Log("xml file:" + path + " not exist", LogType.Error);
        }
        else {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml.text);

            XmlNodeList nodLst = doc.SelectSingleNode("root").ChildNodes;

            for (int i = 0; i < nodLst.Count; i++) {
                XmlElement ele = nodLst[i] as XmlElement;

                if (ele.GetAttributeNode("ID") == null) {
                    continue;
                }
                int ID = Convert.ToInt32(ele.GetAttributeNode("ID").InnerText);
                SkillActionCfg smc = new SkillActionCfg {
                    ID = ID
                };

                foreach (XmlElement e in nodLst[i].ChildNodes) {
                    switch (e.Name) {
                        case "delayTime":
                            smc.delayTime = int.Parse(e.InnerText);
                            break;
                        case "radius":
                            smc.radius = float.Parse(e.InnerText);
                            break;
                        case "angle":
                            smc.angle = int.Parse(e.InnerText);
                            break;
                        
                    }
                }
                skillActionDic.Add(ID, smc);
            }
        }
    }
    public SkillActionCfg GetSkillActionCfg(int id) {
        SkillActionCfg smc = null;
        if (skillActionDic.TryGetValue(id, out smc)) {
            return smc;
        }
        return null;
    }
    #endregion

    #region 技能配置
    private Dictionary<int, SkillMoveCfg> skillMoveDic = new Dictionary<int, SkillMoveCfg>();
    private void InitSkillMoveCfg(string path) {
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml) {
            PECommon.Log("xml file:" + path + " not exist", LogType.Error);
        }
        else {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml.text);

            XmlNodeList nodLst = doc.SelectSingleNode("root").ChildNodes;

            for (int i = 0; i < nodLst.Count; i++) {
                XmlElement ele = nodLst[i] as XmlElement;

                if (ele.GetAttributeNode("ID") == null) {
                    continue;
                }
                int ID = Convert.ToInt32(ele.GetAttributeNode("ID").InnerText);
                SkillMoveCfg smc = new SkillMoveCfg {
                    ID = ID
                };

                foreach (XmlElement e in nodLst[i].ChildNodes) {
                    switch (e.Name) {
                        case "delayTime":
                            smc.delayTime = int.Parse(e.InnerText);
                            break;
                        case "moveTime":
                            smc.moveTime = int.Parse(e.InnerText);
                            break;
                        case "moveDis":
                            smc.moveDis = float.Parse(e.InnerText);
                            break;
                    }
                }
                skillMoveDic.Add(ID, smc);
            }
        }
    }
    public SkillMoveCfg GetSkillMoveCfg(int id) {
        SkillMoveCfg smc = null;
        if (skillMoveDic.TryGetValue(id, out smc)) {
            return smc;
        }
        return null;
    }
    #endregion
    
    #region 怪物

    private Dictionary<int, MonsterCfg> monsterCfgs = new Dictionary<int, MonsterCfg>();

    private void InitMonsterCfg(string path){
        TextAsset xml = Resources.Load<TextAsset>(path);
        if (!xml){
            PECommon.Log("xml file:" + path + " not exists", LogType.Error);
        }
        else{
            var doc = new XmlDocument();
            doc.LoadXml(xml.text);
            XmlNodeList nodeList = doc.SelectSingleNode("root").ChildNodes;
            for (var i = 0; i < nodeList.Count; ++i){
                var element = nodeList[i] as XmlElement;
                if (element.GetAttributeNode("ID") == null){
                    continue;
                }

                var ID = Convert.ToInt32(element.GetAttributeNode("ID").InnerText);
                MonsterCfg mc = new MonsterCfg{
                    ID = ID,
                    bps = new BattleProps()
                };
                foreach (XmlElement xmlElement in nodeList[i].ChildNodes){
                    switch (xmlElement.Name){
                        case "mName":
                            mc.mName = xmlElement.InnerText;
                            break;
                        case "resPath":
                            mc.resPath = xmlElement.InnerText;
                            break;
                        case "hp":
                            mc.bps.hp = int.Parse(xmlElement.InnerText);
                            break;
                        case "ad":
                            mc.bps.ad = int.Parse(xmlElement.InnerText);
                            break;
                        case "ap":
                            mc.bps.ap = int.Parse(xmlElement.InnerText);
                            break;
                        case "addef":
                            mc.bps.addef = int.Parse(xmlElement.InnerText);
                            break;
                        case "apdef":
                            mc.bps.apdef = int.Parse(xmlElement.InnerText);
                            break;
                        case "dodge":
                            mc.bps.dodge = int.Parse(xmlElement.InnerText);
                            break;
                        case "pierce":
                            mc.bps.pierce = int.Parse(xmlElement.InnerText);
                            break;
                        case "critical":
                            mc.bps.critical = int.Parse(xmlElement.InnerText);
                            break;
                    }
                }
                monsterCfgs.Add(ID, mc);
            }
        }
    }

    public MonsterCfg GetMonsterCfgData(int id){
        MonsterCfg cfg;
        if (this.monsterCfgs.TryGetValue(id, out cfg)){
            return cfg;
        }

        return null;
    }

    #endregion
}
